Ink Filepicker makeDropPane on html/body, dragLeave fired immediately after dragEnter - filepicker.io

I am trying to attach a Ink Filepicker handler on the whole viewport, so that the user can drop files everywhere in the page. Here is the code i've been trying so far:
window.filepicker.makeDropPane $("html")[0], # or $("body")[0]
mimetype: "image/*"
multiple: true
dragEnter: -> console.log "dragenter fired"
dragLeave: -> console.log "dragleave fired"
onSuccess: (files) -> # do stuff
onError: (type, message) => # do other stuff
onProgress: (percent) -> # do other stuff
Every time I drag the files in the browser, the dragLeave is fired immediately after the dragEnter, making impossible for me to do stuff.
Furthermore, if I put a div on top of everything to which I create the Filepicker pane, I obviously cannot interact with the page content anymore, unless I recognize the dragenter event independently by the one triggered by Filepicker so that i can change the z-index on-the-fly.
Let me know if i am not clear.
Thanks in advance.

Related

How to force a DOM element to update before others or show a waiting indicator in Svelte?

I have some checkboxes that when clicked will cause a lot of changes in the DOM, and this freezes up the application for several seconds. I'd like the checkboxes to update first, and/or display a waiting indicator. I've tried different things but for some reason nothing else in the DOM will update before the freeze. The changes are made to a large table, either removing or adding entire columns, and it acts as if this has higher priority over anything else because any other attempts to update the DOM after clicking the checkbox don't go through until the table has completed re-rendering. FWIW I can use console.log to display a message before the table updates, and also after it completes for some reason.
import {tick} from "svelte";
let checked = false;
$: applyChanges(checked);
async function applyChanges() {
messageVisible = true
await tick()
requestAnimationFrame(() => {
requestAnimationFrame(() => {
// do the stuff that causes a lots of dom updates
})
})
}
The await tick() applies the messageVisible changes to the DOM.
The double raf will wait for the browser to draw the updated DOM.

How to prevent closing of cell editing in ag-grid on "Other Cell Focus"

I am working on an editable table in Angular application with ag-grid library. I would like to keep editing cells (in full row edit mode) until I finish with it and then close the editors manually via API. The problem is that the editor is closing on other cell click/focus (on some other line) as described here:
The grid will stop editing when any of the following happen:
Other Cell Focus: If focus in the grid goes to another cell, the editing will stop.
I cannot figure out how to disable this, if it is possible. Installing the onCellMouseDown() hook does not help, because the cellFocused event is fired before cellMouseDown. Therefore, the editing stops before I have a chance to intercept the mousedown event.
Here is my stackblitz little extract with related pieces of code.
The need for such scenario is that I want to validate the entry and not to allow a used to quit the editing if the form is not valid. The only workaround I found so far is that on any click outside of editing cells when the editor closing I reopen it right away in onRowEditingStopped() hook unless the editor has been closed via 'OK' button.
After all, I have managed to provide a custom solution that fits exactly into this problem which I was facing also.
First thing is to disable pointer events to non edited rows when a specific row is currently being edited. On Ag-grid's 'cellEditingStarted' callback I have added the following code:
public cellEditingStarted(event: any): void {
//not all rows are on dom ag-grid takes care of it
const nonSelectedGridRows = document.querySelectorAll('.ag-grid-custom-row:not(.ag-row-selected):not(.ag-row-editing):not(.pointer-events-none)');
forEach(nonSelectedGridRows, row => {
row.classList.add("pointer-events-none");
});
}
Because not all rows exist on dom (Ag-grid creates and destroys while you are scrolling )when a specific cell is being edited, I have also added a rowClassRule which is applied when rows are being created:
this.rowClassRules = {
'pointer-events-none': params => {
if (params.api.getEditingCells().length > 0) {
return true;
}
return false;
}
};
scss:
.pointer-events-none {
pointer-events: none
}
By disabling pointer events, when you click on a non edited cell the cell won't get focus and thus the currently edited cell will stil remain on edit mode. You can provide your own custom validation solution and close the editor manually through API. When you are done, you have to enable pointer events to all grid rows back again:
private enablePointerEvents(): void {
//not all rows are on dom ag-grid takes care of it
const nonSelectedGridRows = document.querySelectorAll('.ag-grid-custom-row.pointer-events-none');
forEach(nonSelectedGridRows, row => {
row.classList.remove("pointer-events-none");
});
}
I implemented the same above approach in Ag-Grid React.
I used getRowStyle callback for adding the css pointerEvents: none on dynemic basis.
It seems to be working for me fine.
Please refer the below code
const getRowStyle = (params) => {
// this is not initialized in read mode
// condition for me ==> currentEditRowIndex.current !== null && params.node.rowIndex !== currentEditRowIndex.current
if (someCondition for Row other than inline edit row) {
return { pointerEvents: "none" };
}
return null;
};
After adding this whenver you start the editing..You will need to call redrawRows so that css changes can be applied.
Hope this will help. Thank You!!
Thought I would share another solution that has been working out okay for me so far.
Using 'pointer-events-none' as suggested in the other answer is flawed because the Enter key can also close the editor.
In my case, I want to prevent the editor from closing when client side validation has failed and the data is invalid. When my conditions are met, I call stopPropagation() on the events to prevent the editor close from happening in the first place. It still has potential problems:
It cancels mousedown, dblclick, keydown, focusout and click for all elements that have a class name starting with ag- so if you happen to use this class prefix for other controls on the page, it could interfere. It also means any controls within the grid (sorting, resizing, etc.) don't work while the condition is met.
Calling stopPropagation() could potentially interfere with your own custom controls. So far I've been okay if I dont use the ag- prefix within the markup from my own custom cell editors and renderers
I hope they can add a proper API function to cancel the row/cell stopEditing function in the future.
["mousedown", "dblclick", "keydown", "focusout", "click"].forEach(function (eventName) {
document.addEventListener(eventName, function (e) {
if ( conditionForCancelingIsMet() ) {
// this appears to cancel some events in agGrid, it works for
// preventing editor closing on clicking other cells for example.
// It would be ideal if this worked for all ag-grid specific events
// and had a proper public API to use!
e["__ag_Grid_Stop_Propagation"] = true;
}
// convert element classList to normal js array so we can use some()
var classArray = [].slice.apply(e.target.classList);
if ( conditionForCancelingIsMet() && classArray.some(c => c.startsWith("ag-")) ) {
// unfortunately some events like pressing the 'enter' key still
// require stopPropagation() and could potentially interfere with unrelated controls
e.stopPropagation();
}
}, true);
});

Fullcalendar add static events using modal duplicates rendered entries

I am trying to add static "Training"-events using a button located in a modal.
So what should happen: Clicking on a day or a range of days in fullcalendar opens a modal. In this modal a button is available to "add a training event".
I am using this modal because it shall be possible to add other events in future. Not just trainings.
The modal opens fine and clicking the button adds a new entry in fullcalendar. Clicking on a further day opens the modal again. If now the "add a training button" is clicked again, the new event is rendered twice. One event is rendered on the day i have clicked in the first step, the second is rendered at the day i have clicked now.
Step1:
clicking a day opens the modal
Step2:
clicking the button in the modal adds a new entry
Step3: repeating step1 on another day
Step4:
clicking the button again renders the event twice
Image: Step1-4
This is my js-code. What i am doing wrong?
var calendar = $(calendar).fullCalendar({
header: {
left: 'prev,next today',
center: 'title',
right: 'month,agendaWeek,agendaDay'
},
defaultDate: new Date(),
navLinks: true, // can click day/week names to navigate views
selectable: true,
selectHelper: true,
select: function (start, end) {
$('#fc_create').click(); // opens modal
$('.addTraining').on("click", function () { // clicking "add training button"
var eventData;
eventData = {
title: "Training",
start: start,
end: end
};
$('#calendar').fullCalendar('renderEvent', eventData);
$('.close').click();
})
},
editable: true,
eventLimit: true
});
Every time your "select" callback runs, you are adding another new "click" event handler to the "addTraining" element(s). So if "select" runs 3 times, then the "click" event will be declared 3 times, and when "addTraining" is clicked, 3 versions of the same code will run. Javascript allows multiple handlers for the same event to be attached to an element at once, so you are just building them up each time the "select" callback runs, without ever removing them.
To fix this you can either:
1) Declare the handler once - do it page load, outside your fullCalendar declaration. This will give you a problem in that you won't have direct access to the "start"/"end" values from the select callback. You can get round this by using global variables (yuck) or perhaps putting the values in hidden fields or data- attributes somewhere suitable, and then the click handler can find them each time it runs.
2) Using jQuery's "on" and "off" syntax to first remove the previous handler, and then add a new one, so only one handler is ever active at any one time. See http://api.jquery.com/off/ and http://api.jquery.com/on/ for more details and examples. I can provide a sample if necessary.

wxPython: How to handle event binding and Show() properly

I'm just starting out with wxPython and this is what I would like to do:
a) Show a Frame (with Panel inside it) and a button on that panel.
b) When I press the button, a dialog box pops up (where I can select from a choice).
c) When I press ok on dialog box, the dialog box should disappear (destroyed), but the original Frame+Panel+button are still there.
d) If I press that button again, the dialog box will reappear.
My code is given below. Unfortunately, I get the reverse effect. That is,
a) The Selection-Dialog box shows up first (i.e., without clicking on any button since the TopLevelframe+button is never shown).
b) When I click ok on dialog box, then the frame with button appears.
c) Clicking on button again has no effect (i.e., dialog box does not show up again).
What am I doing wrong ? It seems that as soon as the frame is initialized (even before the .Show() is called), the dialog box is initialized and shown automatically.
I am doing this using Eclipse+Pydev on WindowsXP with Python 2.6
============File:MainFile.py===============
import wx
import MyDialog #This is implemented in another file: MyDialog.py
class TopLevelFrame(wx.Frame):
def __init__(self,parent,id):
wx.Frame.__init__(self,parent,id,"Test",size=(300,200))
panel=wx.Panel(self)
button=wx.Button(panel, label='Show Dialog', pos=(130,20), size=(60,20))
# Bind EVENTS --> HANDLERS.
button.Bind(wx.EVT_BUTTON, MyDialog.start(self))
# Run the main loop to start program.
if __name__=='__main__':
app=wx.PySimpleApp()
TopLevelFrame(parent=None, id=-1).Show()
app.MainLoop()
============File:MyDialog.py===============
import wx
def start(parent):
inputbox = wx.SingleChoiceDialog(None,'Choose Fruit', 'Selection Title',
['apple','banana','orange','papaya'])
if inputbox.ShowModal()==wx.ID_OK:
answer = inputbox.GetStringSelection()
inputbox.Destroy()
There are a number of ways to do this, but to make the least number of changes to your code,
Change def start(parent): to
def start(parent, evt):
And change button.Bind(wx.EVT_BUTTON, MyDialog.start(self)) to
button.Bind(wx.EVT_BUTTON, lambda evt: MyDialog.start(self, evt))
That is, the second argument in Bind needs to be a function that takes and event, and you need to create the dialog box when the button is clicked. lambda makes this a function that also takes parent and evt (you can also use functools.partial for version >2.5), and then when the button is clicked, start will be called to create the dialog.
I'm not quite sure what's going on in your code, but it seems that you're calling start and creating the dialog in your initial call to Bind, and then passing the return value from start, None to Bind.
Note 1
In more detail, the reason to use the lambda here is that Bind should have a form like Bind(event, handler) where event is a wx.PyEventBinder, like wx.EVT_BUTTON, and handler is a function like foo(evt) where evt is a wx.Event or wx.CommandEvent. (There's no recursion here, as you're just saying what to do when something happens, but that thing hasn't happened yet, so the event hasn't been created. When the event does happen, it will be represented by a wx.Event, which will have information about the event, like where the mouse was when it was clicked, etc.)
Note 2
In my answer I tried to answer your question with minimal changes as I thought that would be easiest. Maybe the code below is more clear (and maybe it's generally clearest to handle events within the widget that creates them):
def start2(parent):
inputbox = wx.SingleChoiceDialog(parent,'Choose Fruit', 'Selection Title',
['apple','banana','orange','papaya'])
if inputbox.ShowModal()==wx.ID_OK:
answer = inputbox.GetStringSelection()
inputbox.Destroy()
class TopLevelFrame2(wx.Frame):
def __init__(self,parent,id):
wx.Frame.__init__(self,parent,id,"Test",size=(300,200))
panel=wx.Panel(self)
button=wx.Button(panel, label='Show Dialog', pos=(130,20), size=(60,20))
# Bind EVENTS --> HANDLERS.
button.Bind(wx.EVT_BUTTON, self.OnClick)
def OnClick(self, evt):
start2(self)

Dojo: dijit.form.select won't fire "onClick" event the first time clicked

I've been through the Dojo docs as well as the API and tried Google but can't find a solution to my problem, I hope anybody here can help me out.
I'm trying to create a dijit.form.select programmatically (using Dojo 1.4) and connect to the "onClick"-event of the widget.
Here's a part of my code:
var dataSelect = new dijit.form.Select({
id : "myselect",
name : "myselect",
labelAttr: "label",
labelType: "html"
},
"selectid");
dataSelect.addOption({value: "value", label: "first item label"});
dojo.connect(dataSelect, "onClick", function() {
alert("clicked!");
});
What it does: A select-box is created replacing an input-field with the ID "selectid", an option "first item label" is created. Everythings all right until here.
Then I connect to the "onClick"-event of the select, which is supposed to load more options via AJAX (but will just display an alert for testing purposes in this example).
The problem: When I click on the little arrow next to the dropdown, the event is fired (OK). But when I click on the select box itself (the area containing the option), the event is NOT fired the first time I click it (unless I clicked on the arrow before).
When I click the select box a second time (and every time after that), the event will fire!
I've tried to use "onFocus" instead of "onClick" which does work, but then the dropdown will not open when first clicked, even if I use the "openDropDown"-function (which does work when connecting to "onClick"!).
Is it me, did I run into a Dojo bug or is it a strange feature I just don't get?
Any help is appreciated.
Greetings,
Select0r
Here is a cross-browser solution:
var sizeSelect = new dijit.form.Select({
id: "sizeSelect",
name: "state",
options: size,
onChange: function(val) {
dojo.style(dojo.byId("textInput"), {"fontSize":val});
}
}, "sizeSelect");
Try to connect not to the widget itself but to it's dom node:
dojo.connect(dataSelect.domNode, "onclick", function() {
alert("clicked!");
});
Select (which extends _HasDropDown) has fancy code to handle:
mouse down on select widget
mouse move to one of the options
mouse up
Maybe that's canceling the click event.
Maybe you can connect to _loadChildren() instead.
The root cause for this issue is that the _onDropDownMouseDown method of dijit._HasDropDown will manipulate the dom node, which cause the e.target of onmousedown and onmouseup changes for the first initialization.
As we know, the onclick event will be triggered only when the target of onmousedown and onmouseup are the same target.
So in this case, the onclick event is not triggered.
It seems that in Dojo 1.5, the problem still remains.