autoZoom in zoomcharts (netchart 1.6.0) does not prevent nodes moving out of view - zooming

Although autozoom is on, nodes keep moving out of view. Automatic zoom to keep all nodes in view does not happen.
My console shows this:
interaction: Object
panning: Object
resizing: Object
selection: Object
zooming: Object
autoZoom: true
autoZoomDuration: 500
autoZoomSize: 0.9
doubleClickZoom: 1.5
fingers: true
sensitivity: 1
wheel: true
I create nodes with this function
function graphDoubleClick(event){
$("#nodemenu").css("display", "none");
$("#linkmenu").css("display", "none");
if (event.clickNode && event.shiftKey){//test the click was on a node
chart.addData({
nodes:[{
"id":"n"+nextId,
"type":"unknown",
"x":event.chartX,
"y":event.chartY,
"loaded":true,
"style":{"label":"newNode"}
}],
links:[{
"id":"ll"+nextId,
from:event.clickNode.id,
to:"n"+nextId,
"style":{"label":"unknown"}
}]
});
nextId += 1;
}
else if (!event.clickNode && !event.clickLink && event.shiftKey){
chart.addData({
nodes:[{
"id":"n"+nextId,
"loaded":true,
"type":"unknown",
"x":event.chartX,
"y":event.chartY,
"style":{"label":"newNode"}
}]
});
nextId += 1;
};
}
What could cause this behaviour?

Default doubleClick action is zoom in and it internally disables auto zoom.
Add event.preventDefault() at the end of graphDoubleClick and you should be fine.
Or disable zoom on double click by setting settings.interaction.zooming.doubleClickZoom = 0.

Related

How to define a variable that's gonna be retrieved from localstorage (Chrome extension)?

I have a variable defined like this (not sure if it should be with let or var in the first place):
let activated = false;
The first thing that the extension should do is check the value of activated. I think this is the correct syntax:
chrome.storage.local.get(['activated'], function(result) {
activated = result.activated
alert ("activated: " + result.activated)
});
After some logic, I want to change activetedto true, with this syntax:
chrome.storage.local.set({activated: true}, function() {
console.log("activated changed to true: " + activated)
});
However, when I close and open the browser again, activatedis set to false again.
How should I structure this in order to achieve the desired result?
The way to acess a localstorage variable isn't by defining as I was doing in let activated = false;.
The way to add the variable retrieved from localstorage to the program's control flow should be done this way:
chrome.storage.local.get(['activated'], function(result) {
if (result.activated == value) { // Do something }
});

How to disable the context menu on long press when using device mode in Chrome?

How to disable the context menu on long press when using device mode in Chrome ?
I mean this context menu:
I am asking this because I want to debug long press gestures for mobile devices and the context menu causes my react app to behave in a strange way:
when I try to reorder the list then "strange things start to happen": selected item starts to float all over the place (as can be seen from snapshot below). The Hello World is obscured by the selected item. Really strange.
My workaround is entering this code into the JS console when testing long press actions in device mode:
window.oncontextmenu = function() { return false; }
I have developed a slightly more "advanced" workaround that will still (most of the time) show the contextmenu on right-click while preventing it from showing on a simulated long-tap:
window.oncontextmenu = function() {
if (event.button != 2 && !(event.clientX == event.clientY == 1)) {
event.preventDefault();
}
}
#marsk comment was right therefore based on previous answers I come up with another solution using PointerEvent.pointerType
window.oncontextmenu = function (event: any) {
// eslint-disable-next-line no-console
console.log(event); // prints [object PointerEvent]
const pointerEvent = event as PointerEvent;
// eslint-disable-next-line no-console
console.log(`window.oncontextmenu: ${pointerEvent.pointerType}`);
if (pointerEvent.pointerType === 'touch') {
// context menu was triggerd by long press
return false;
}
// just to show that pointerEvent.pointerType has another value 'mouse' aka right click
if (pointerEvent.pointerType === 'mouse') {
// context menu was triggered by right click
return true;
}
// returning true will show a context menu for other cases
return true;
};

Prevent chrome.notifications API from hiding my notification after a few seconds

I'm doing around 1-2 notifications a day and it's important the user doesn't miss it. Is there a way of removing the auto close and only allowing the user to manually close the notification?
I don's see any option for this in the Notification Options:
http://developer.chrome.com/extensions/notifications.html#type-NotificationOptions
Notification now has (since Chrome 50) a requireInteraction property to force the notification to stay on screen:
var notification = new Notification("TITLE", {
icon: 'assets/res/icon.png',
body: "MESSAGE",
requireInteraction: true
});
In onclick you have to close the notification:
notification.onclick = function()
{
this.close();
}
UPDATE (2016-05-24):
Xan commented:
Fun fact: all this arcane hacking is no longer needed; see the new requireInteraction flag
It is availalbe since Chrome 50. More info.
Thanks to root's comment, this answer is revised to account for the fact that the onClosed event is not fired when the notification disappears (into the notigications area) after a few seconds. This is still kind of a hacky solution.
Background
You can take advantage of the fact that a notification's life-cycle ends with one of the following events:
onClosed: When the user clicks on the small 'x' in the top-right corner.
onClicked: When the user clicks on the message body (not the 'x', not some button).
onButtonClicked: When the user clicks on one of the buttons (if any).
The solution
The proposed solution consists of the following steps:
Register listeners for all the events mentioned above.
Register a timeout after a few seconds (e.g. 30) -after the notification is hidden- that will delete and re-create the notification (so it effectively stays visible on the screen.
If any of the listeners set on step 1 fires, it means the user interracted with the notification, so cancel the timeout (you don't need to re-create the notification).
Writing about it is simple, coding takes some more effort :)
Here is the sample code I used to achieve what is described above:
In manifest.json:
{
"manifest_version": 2,
"name": "Test Extension",
"version": "0.0",
"background": {
// We need this for the `Timeout` - see notes below
"persistent": true,
"scripts": ["background.js"]
},
"browser_action": {
"default_title": "Test Extension"
"default_icon": {
"19": "img/icon19.png",
"38": "img/icon38.png"
},
},
"permissions": ["notifications"]
}
In background.js:
var pendingNotifications = {};
/* For demonstration purposes, the notification creation
* is attached to the browser-action's `onClicked` event.
* Change according to your needs. */
chrome.browserAction.onClicked.addListener(function() {
var dateStr = new Date().toUTCString();
var details = {
type: "basic",
iconUrl: "/img/notifIcon.png",
title: "REMINDER",
message: dateStr + "\n\n"
+ "There is one very important matter to attend to !\n"
+ "Deal with it now ?",
contextMessage: "Very important stuff...",
buttons: [
{ title: "Yes" },
{ title: "No" }
]
};
var listeners = {
onButtonClicked: function(btnIdx) {
if (btnIdx === 0) {
console.log(dateStr + ' - Clicked: "yes"');
} else if (btnIdx === 1) {
console.log(dateStr + ' - Clicked: "no"');
}
},
onClicked: function() {
console.log(dateStr + ' - Clicked: "message-body"');
},
onClosed: function(byUser) {
console.log(dateStr + ' - Closed: '
+ (byUser ? 'by user' : 'automagically (!?)'));
}
};
/* Create the notification */
createNotification(details, listeners);
});
/* Create a notification and store references
* of its "re-spawn" timer and event-listeners */
function createNotification(details, listeners, notifId) {
(notifId !== undefined) || (notifId = "");
chrome.notifications.create(notifId, details, function(id) {
console.log('Created notification "' + id + '" !');
if (pendingNotifications[id] !== undefined) {
clearTimeout(pendingNotifications[id].timer);
}
pendingNotifications[id] = {
listeners: listeners,
timer: setTimeout(function() {
console.log('Re-spawning notification "' + id + '"...');
destroyNotification(id, function(wasCleared) {
if (wasCleared) {
createNotification(details, listeners, id);
}
});
}, 10000)
};
});
}
/* Completely remove a notification, cancelling its "re-spawn" timer (if any)
* Optionally, supply it with a callback to execute upon successful removal */
function destroyNotification(notifId, callback) {
/* Cancel the "re-spawn" timer (if any) */
if (pendingNotifications[notifId] !== undefined) {
clearTimeout(pendingNotifications[notifId].timer);
delete(pendingNotifications[notifId]);
}
/* Remove the notification itself */
chrome.notifications.clear(notifId, function(wasCleared) {
console.log('Destroyed notification "' + notifId + '" !');
/* Execute the callback (if any) */
callback && callback(wasCleared);
});
}
/* Respond to the user's clicking one of the buttons */
chrome.notifications.onButtonClicked.addListener(function(notifId, btnIdx) {
if (pendingNotifications[notifId] !== undefined) {
var handler = pendingNotifications[notifId].listeners.onButtonClicked;
destroyNotification(notifId, handler(btnIdx));
}
});
/* Respond to the user's clicking on the notification message-body */
chrome.notifications.onClicked.addListener(function(notifId) {
if (pendingNotifications[notifId] !== undefined) {
var handler = pendingNotifications[notifId].listeners.onClicked;
destroyNotification(notifId, handler());
}
});
/* Respond to the user's clicking on the small 'x' in the top right corner */
chrome.notifications.onClosed.addListener(function(notifId, byUser) {
if (pendingNotifications[notifId] !== undefined) {
var handler = pendingNotifications[notifId].listeners.onClosed;
destroyNotification(notifId, handler(byUser));
}
});
Final notes:
If your notifications are extremely important, you should implement a "recovery" mechanism, for case such as browser os OS crashes or abrupt termination. E.g. relying on a more persistent storage (localStorage, chrome.storage API etc), resuming pending notifications on extension/browser start-up etc.
It might be a good idea to put a limit on the total number of pending notifications, for "user-friendliness" reasons. If your pending notifications exceed, say, 3 at any given moment, you could replace them with one that informs there are pending notifications and direct the user to a page where you list all of them. (The code will be considerably more complex, but hey anything for the user, right ? ;)
Instead of trying to keep the notifications visible on screen until the user decides to deal with them, it could be better using a Badge (wich can have a color and a small text - indicating the number of pending notifications.
I haven't looked into it, but it might be possible (in which case it is advisable as well) to replace the Timeout's with the chrome.alarms API and then convert the background-page to non-persistent (a.k.a. event-page) which will make it more resource-friendly.
This answer is obsolete; see this answer for an up to date solution involving requireInteraction flag (Chrome 50+).
There is a slightly better (but again, hacky) solution.
When you call update on a notification that changes its priority, and the priority is 0 or above, the notification will be re-shown and the timer for hiding it reset.
So, you can show a notification with a high priority, (say, 2) and then repeat this on an interval shorter than time to hide the notification:
chrome.notifications.update(id, {priority : 1}, function(wasUpdated) {
if(wasUpdated) {
chrome.notifications.update(id, {priority : 2}, function() {});
} else {
// Notification was fully closed; either stop updating or create a new one
}
});
UPDATE answar: after Chrome 50, please add new attribute: [requireInteraction: true]!
don't use chrome.notifications.create
try to use var notification= new Notification("New mail from John Doe", { tag: 'msg1', requireInteraction: true});
will not to close.
if want to close=> notification.close();
ref: http://www.w3.org/TR/notifications/
https://developer.mozilla.org/en-US/docs/Web/API/notification/requireInteraction
webkit notifications seem to be more persistent on the screen, althouth they have the opposite problem - how to hide them to sys tray.
http://developer.chrome.com/extensions/desktop_notifications.html

Mootools squeezebox handler removing hidden div element

Hidden div element content is removed after first modal popup display.
Using the below handler function, the modal displays the hidden div just fine, then after clearing the modal, a subsequent call to the below handler function returns an alert that the "Target does not exist", and the hidden dive element is in fact gone.
function OnSubmitHandler() {
if (e = $('modalcontainer')) {
SqueezeBox.initialize({
size : {x : 300, y : 120}
});
SqueezeBox.open(e, {
handler : 'adopt',
overlayOpacity : 0.7,
onOpen : function(){
e.style.display = 'block';
},
onClose : function(){
e.style.display = 'none';
}
});
}else{
alert('Target does not exist');
}
}
This should be simple and the handler function works fine as written, but the hidden div content is gone after the first display. Having trouble figuring out why. I must be missing something.
Because you adopt the content, it is moved in the DOM to your squeezebox. Since you don't reuse your squeezebox instance and initialize it every time, on the next init it will empty the content area (still containing the e) and have nothing further to adopt.
Reuse the instance or see if it supports clone instead. Also you can move e back to dom or even just as reference onClose - do e.dispose() to protect it. Then do e = e || $() but keep it as a scoped var and not global
change
if (e = $('modalcontainer')) {
to
var e = $('modalcontainer');
var e = e.clone();
if (e) {
This way you create an exact copy of the element you wish to display (save for the id of the clone) and then the adopt handler disposes of the clone for you on close, so you don't have to worry about a memory leak.

Terms+Conditions dialog in backbone.js

I'd like to throw up a T+C dialog when one clicks the submit button of a form. I'm using backbone.js. I can't work out whether I should be cramming the dialog within the FormView, or invoking the DialogView from within FormView or hooking it up with an event or something.
Ideally, my FormView Save() method would initialize it, with a Accept and Decline callback. My previous, none-Backbone implementation handed over all control to the dialog itself, which was a bit inelegant. Can anyone suggest anything?
edit: Thanks to Derick, here's where I'm at. Note however, that JqueryUI dialog appends itself at the end of 'body', and thus looses its context (it's not longer wrapped in the div it came from), so event binding isn't working.
save: ->
that = #
dlg = new TermsConditionsView({el: '#tcDialog'})
dlg.bind 'accepted', #tncAccepted, #
dlg.bind 'declined', #tncDeclined, #
$(dlg.render().el).dialog
draggable: false
resizable: false
width: 500
height: 600
modal: true
dialogClass: 'termsConditions'
buttons: [
{
id: 'acceptButton'
text: 'Accept'
click: -> that.tncAccepted()
}
{
id: 'declineButton'
text: 'Decline'
click: -> that.tncDeclined()
}
]
I'd have the FormView call a separate DialogView, and listen to an "accepted" and "declined" event, which the DialogView will trigger based on the user's action.
FormView = Backbone.View.extend({
events: {
"click #save": "save"
},
save: function(){
var dlg = new TnCView();
dlg.bind("accepted", this.tncAccepted, this);
dlg.bind("declined", this.tncDeclined, this);
$(dlg.render().el).dialog();
},
tncAccepted: function(){
// do whatever you need, when the user accepts the terms n conditions
},
tncDeclined: function(){
// do whatever you need, when the user declines the terms n conditions
}
});
TnCView = Backbone.View.extend({
events: {
"click #accept": "accept",
"click #decline": "decline"
},
accept: function(){
// close the dialog
this.trigger("accepted");
},
decline: function(){
// close the dialog
this.trigger("declined");
}
});
Note that I put the FormView in control of turning the Terms n Conditions into a dialog. it's my preference for the parent form to be in control of when / where a child form's 'el' is placed into the DOM / shown on the screen. this tends to keep the code cleaner and more flexible in the long run.